"""
作者：Huayu Zong
日期：2023年01月日
"""
import logging
from tkinter import filedialog, dialog
import os
import re
import logging


SingleProgramBlockSize = 1024
FLASH_START_ADDR = 0x08008000   #飞思卡尔单片机内置FLASH起始地址
#将\n替换位\r\n
isReplace_LR_with_CRLF = True


def find_all_indexes_re(input_string, character):
    indexes = [m.start() for m in re.finditer(character, input_string)]
    return indexes

def remove_element_no_download(prm_lines_list):
    # S0 S5 S7 S8 S9 record 无需下载

    no_download_str = ["S0", "S5", "S7", "S8", "S9"]
    print("-----------------------------------------------------")
    print("移除无虚下载到单片机中的S-record：")
    for line in prm_lines_list:
        for s in no_download_str:
            if line.find(s) != -1:
                print(line)
                prm_lines_list.remove(line)
                break
    print("-----------------------------------------------------")




class FileOperation(object):
    def __init__(self):
        self.__full_text = None
        self.__full_lines_list = []
        self.fixed_size_program_list = []
        self.file_total_size = 0
        self.single_block_prm_info_dict = {}
        self.program_block_count = 0
        self.send_prm_block_index = 0
        self.update_percent = 0  # 0~100

    def clear_variable_value(self):
        self.__full_text = None
        self.__full_lines_list = []
        self.fixed_size_program_list = []
        self.file_total_size = 0
        self.single_block_prm_info_dict = {}
        self.program_block_count = 0
        self.send_prm_block_index = 0
        self.update_percent = 0

    # 读取文件(一次性读完)
    def open_file_with_select_file(self):
        path = filedialog.askopenfilename(title=u'选择文件',
                                          filetypes=[('FreescaleCodeWarrior', '*.s19 '), ('All files', '*')],
                                          initialdir=(os.path.expanduser('F:\研究生资料\ShareFolders\研究生20220514\0导师\远程更新程序\基于4G模块OTA\APP程序模板\App-Program\bin')))
        if path is not None:
            with open(file=path, mode='r', encoding='utf-8') as file:
                try:
                    text = file.read()
                    print(f"origin file size {os.path.getsize(path)}")

                    if isReplace_LR_with_CRLF:
                        self.__full_text = text.replace('\n', "\r\n")  # 将“\n”替换为“\r\n”
                    else:
                        self.__full_text = text

                finally:
                    file.close()
        pass

    # 按行读取文件
    def open_file_with_line(self):
        path = filedialog.askopenfilename(title=u'选择文件',
                                          filetypes=[('FreescaleCodeWarrior', '*.s19 '), ('All files', '*')],
                                          initialdir=(os.path.expanduser('F:\研究生资料\ShareFolders\研究生20220514\0导师\远程更新程序\基于4G模块OTA\APP程序模板\App-Program\bin')))
        if not path:
            return -1


        with open(file=path, mode='r', encoding='utf-8') as file:
            try:
                while True:
                    text = file.readline()
                    #文件读取结束
                    if not text:
                        break

                    if isReplace_LR_with_CRLF:
                        text = text.replace('\n', "\r\n")  # 将“\n”替换为“\r\n”
                    self.__full_lines_list.append(text)

                # 打印原始文件size和数据
                print(f"origin file size {os.path.getsize(path)}, data: {self.__full_lines_list}")
            finally:
                file.close()
        return 0
        pass

    #将文件分成固定大小的字符串
    '''
    def split_into_fixed_size_text(self):
        #self.open_file_with_select_file()
        self.open_file_with_line()
        os.system("pause")

        index_list = self.find_all_indexes_re(self.__full_text, '\n')
        print(index_list)

        text = self.__full_text
        while len(text) > 0:
            self.fixed_size_program_list.append(text[:SingleProgramBlockSize])
            text = text[SingleProgramBlockSize:]

        self.program_block_count = len(self.fixed_size_program_list)
        pass
    '''

    '''
    # 按行位基本单位，字符串按固定大小分配，前提是最后一行字符串必须是完整的，不可被截断
    def split_into_fixed_size_text(self):
        # 打开文件
        self.open_file_with_select_file()
        

        # 用新的符号引用
        text = self.__full_text
        str_list = self.fixed_size_program_list

        indexes = find_all_indexes_re(text, '\n')
        print("index of '\\n' list: ", indexes)
        split_indexs = []

        start = 0
        i_before = 0
        for i in indexes:
            if i - start > (SingleProgramBlockSize - 1):
                #print(i)
                start = i
                split_indexs.append(i + 1)
            elif i == indexes[len(indexes) - 1]:
                split_indexs.append(i + 1)
        print("split_indexs: ", split_indexs)

        # 拆分出的字符串放入list
        for i in split_indexs:
            if i == split_indexs[0]:
                split_str = text[:i]
            else:
                split_str = text[i_before:i]
            str_list.append(split_str)
            i_before = i

        # 获取 fixed_size_program_list属性
        self.program_block_count = len(self.fixed_size_program_list)
        self.file_total_size = len(self.__full_text)
    '''

    def split_into_fixed_size_text(self):
        if self.open_file_with_line():
            print("file open failed!")
            return

        # 移除无需下载到单片机flash中的程序
        #self.__full_lines_list.pop(0)
        remove_element_no_download(self.__full_lines_list)

        # 判断每一个record的size是否小于block size？
        for l in self.__full_lines_list:
            if len(l) > SingleProgramBlockSize:
                print("ERR: SingleProgramBlockSize set small!!!")
                return

        #
        cur_ele = self.__full_lines_list[0]
        next_ele = None
        for i in range(len(self.__full_lines_list) - 1):
            next_ele = self.__full_lines_list[i + 1]
            if (len(cur_ele) + len(next_ele)) < SingleProgramBlockSize:
                cur_ele = ''.join([cur_ele, next_ele])
            else:
                self.fixed_size_program_list.append(cur_ele)
                cur_ele = next_ele
        # 遍历结束
        self.fixed_size_program_list.append(cur_ele)

        # 获取 fixed_size_program_list属性
        self.program_block_count = len(self.fixed_size_program_list)
        for ele in self.fixed_size_program_list:
            self.file_total_size += len(ele)

    # 在客户端解析S19文件，在使用bsae64编码下发
    def parse_s19_file(self):
        # 打开s19文件
        self.open_file_with_line()

        # 移除无需下载到单片机flash中的程序
        self.__full_lines_list.pop(0)

        for srec in self.__full_lines_list:
            # 删除换行符
            srec = srec.strip()

            #获取类型
            srec_type = srec[0:2]

            # 处理 type record
            addr_s1 = 0
            while True:
                if srec_type == 'S1':
                    addr_s1, data = parse_S1_type(srec)


                elif srec_type == 'S2':
                    parse_S2_type(srec)
                elif srec_type == 'S3':
                    parse_S3_type(srec)

    # 单次更新的程序block信息
    def get_single_program_block_info(self, index):
        self.single_block_prm_info_dict = {
            "FlashStartAddr": str(FLASH_START_ADDR),
            "PrmTotalSize": self.file_total_size,
            "PrmSize": len(self.fixed_size_program_list[index]),
            "PrmData": self.fixed_size_program_list[index]
        }
        print("index:", index,"--", self.single_block_prm_info_dict)

    pass

def parse_S1_type(srec):
    #获取count
    srec_count = int(srec[2:4], 16)
    print(srec_count)

    #获取地址
    srec_addr = int(srec[4:8], 16)
    print(hex(srec_addr))

    #获取数据
    srec_data = int(srec[8:8 + (srec_count - 3)*2], 16)
    print(hex(srec_data))

    return srec_addr, srec_data

def parse_S2_type(srec):
    pass

def parse_S3_type(srec):
    pass
if __name__ == '__main__':

    f = FileOperation()
    f.split_into_fixed_size_text()
    print("fixed size program code list:", f.fixed_size_program_list)
    print(f"elements count of fixed_size_program_list: {f.program_block_count}")
    print(f"need substitute '\\n' with '\\r\\n': 【{isReplace_LR_with_CRLF}】, program size of fixed_size_program_list: 【{f.file_total_size}】")

    for i in range(f.program_block_count):
        f.get_single_program_block_info(i)


